package framework.aop.aspect;

import framework.aop.intercept.InchMethodInterceptor;
import framework.aop.intercept.InchMethodInvocation;

import java.lang.reflect.Method;
/**
 * class for the methods that should run after the point cut method returned
 */
public class InchMethodAfterReturningAdvice extends InchAbstractAspectAdvice implements InchAdvice, InchMethodInterceptor {
    private InchJoinPoint joinPoint;

    /**
     * constructor
     * @param aspectMethod aspect method eg: demo.aspect.logAspect.before( before() is just a method, you can also run it at anyplace)
     * @param aspectTarget aspect class eg: demo.aspect.logAspect
     */
    public InchMethodAfterReturningAdvice(Method aspectMethod, Object aspectTarget) {
        super(aspectMethod, aspectTarget);
    }

    /**
     * invoke method
     * using recursion create by InchMethodInvocation.proceed() and any invoke() in all advice class
     * to implement the aspect method before/after/... the point cut
     * check InchMethodInvocation class to know more
     *
     * @param methodInvocation InchMethodInvocation class
     * @return  returnValue of the point cut(at last of recursion)
     * @throws Throwable
     */
    @Override
    public Object invoke(InchMethodInvocation methodInvocation) throws Throwable {
        //run other aspect methods and point cut method
        Object returnValue = methodInvocation.proceed();
        this.joinPoint = methodInvocation;
        //run the aspect method should run after returning with the return value of the point cut method
        afterReturning(returnValue,joinPoint.getArguments(),joinPoint.getThis());
        return returnValue;
    }

    /**
     * the running of the aspect method check father class InchAbstractAspectAdvice.invokeAdviceMethod to see
     * @param returnValue the returned value of the point cut
     * @param args args for the aspect method
     * @param target the join point (not used in this project)
     * @throws Throwable
     */
    private void afterReturning(Object returnValue,Object[] args, Object target) throws Throwable{
        invokeAdviceMethod(joinPoint,returnValue,null);
    }
}
